Test Message

Naukri Local Judge Mod

開始使用

這是什麼? 能做什麼?

這是一個 C/C++的本地 Judge 模組,它可以在輸入結束後自動幫你比對測資,免除線上判斷時的麻煩和等待時間。

他能夠幫助你:

  1. 取消 4996 警告(scanf()等函式的不安全警告)
  2. 取消 scanf() 不接受回傳值時的警告
  3. 本地 Judge (支援 Tolerant 、 Strictly 、 Special 三種模式)
  4. 簡單的效能評估

安裝

以下為在 Visual Studio 安裝的流程

  1. 下載本模組

  2. 新增一個空白專案,並在專案中加入一個名為 main 的.c 或.cpp 檔

  3. 新增 include 目錄到專案

    專案 → 屬性 → C/C++ → 一般 → 其他 Include 目錄 → 指定模組資料夾

  4. 把模組中的 systemInput.txt、systemOutput.txt、userOutput.txt 移動至專案資料夾 (你寫程式的.c/.cpp 檔那裡)。

    以 Project 專案為例,在 Project/Project/ 這層會看到 main.c,把 3 個 txt 檔丟到這裡。

  5. 如果使用的是 cpp,將模組中全部的.c 檔改為.cpp。

侵入式安裝

這步驟不會為你添加任何實質性的功能,但可以在寫程式時不用再引入本模組的標頭檔,從而獲得更好的使用體驗,但如果除了 Online Judge 之外還要寫其他 C/C++的程式則不建議使用。

  1. 先備份好 stdio.h 避免出錯。

  2. 做完以上述動作後,開啟 main.c 輸出

    #include <stdio.h>

  3. 在上面右鍵 → 前往<stdio.h>

  4. 滑到最下面,在#endif 上加上

    #include <naukri.h>

    變成

    … (其他在上面的程式碼)
    #include <naukri.h>
    #endif

  5. 儲存,如果你的 Visual Studio 沒有該資料夾的存取權限他會提示你另存新檔,把它存到桌面在手動貼到該資料夾覆蓋即可。
    資料夾可以在 stdio.h 頁籤上右鍵 → 開啟收納資料夾找到。

操作

使用方式

選好 Judge 模式(參見判斷模式),在#include <stdio.h> 下引入 naukri.h 變成

#include <stdio.h>
#include <naukri.h>

即可使用,上傳至 OJ 時記得刪掉 #include <naukri.h> 就可以了。
若為侵入式安裝則不必引入(除非你不會用到 stdio.h),像沒安裝模組時一樣寫程式即可。

若你使用的是 cpp,iostream 和 cstdio 內部都會引入 stdio.h。

情境範例

請先閱讀下方的巨集與定義

已經有輸入和正確的輸出
  1. 在 FILE_INPUT 放輸入,在 FILE_COMPARE 放正確的輸出
  2. 定義 IO 模式為 F_TF (FILE_INPUT 輸入、終端 + FILE_OUTPUT 輸出)
  3. 將 CMPMODE 設為 2 (或將函式 main() return 2)
  4. 開始運行。
已經有輸入和正確的程式碼
  1. 在 FILE_INPUT 放輸入
  2. 定義 IO 模式為 F_TF (FILE_INPUT 輸入、終端 + FILE_OUTPUT 輸出)
  3. 將 CMPMODE 設為 3 (或將函式 main() return 3)
  4. 開始運行。
只有正確的程式碼,想用終端機測試
  1. 定義 IO 模式為 T_TF (終端輸入、終端 + FILE_OUTPUT 輸出)
  2. 將 CMPMODE 設為 3 (或將函式 main() return 3)
  3. 開始運行,輸入自定義測資。 (也可以將自定義測資放到 FILE_INPUT 用 “已經有輸入和正確的程式碼” 判斷)
什麼都沒有,只是想使用包裝過的函式
  1. 定義 IO 模式為 T_T (終端輸入、終端輸出)
  2. 將 CMPMODE 設為 1 (或將函式 main() return 1)
  3. 開始運行。

巨集與定義

判斷模式

比較時的預設參數。

CMPMODE

定義預設的 Judge 的方式,而 main.c 的 return 值可以用來覆蓋這個預設模式(也就是如果 return 不為 0 則以 return 值為準)

0 = 隨意(若 return 亦為 0 則不進行比較)
1 = 不進行比較
2 = 使用 FILE_COMPARE 儲存的答案比較
3 = 使用 judge.c 計算出的答案比較 (這個模式只有在使用 FILE_INPUT 作為輸入時才能使用)
4 = 自動判斷,如果輸入來自終端機 = 2, 來自檔案 = 3

STRICTLYMODE

嚴格比對模式,當 STRICTLYMODE 為 0 時代表關閉,亦即是寬容(Tolerant)模式,為 1 時開啟則是嚴格(Strictly)模式,預設值為 0

TLE

定義超時時間限制,以毫秒為單位,預設值為 1000 ms
注意!它不會在你超時時跳出程式,只會在印出判斷結果時提醒你超時了。

文件位置

輸入輸出檔存放位置,可在 naukri.h 進行自定義修改

FILE_INPUT

輸入檔位置,預設值為 input.txt

FILE_OUTPUT

使用者輸出檔位置,預設值為 output.txt

FILE_COMPARE

比對用檔案位置,也是判斷程式輸出檔,預設值為 compare.txt

IO 流

這部分僅供模組使用,若無客製化需求只要注意不要誤用關鍵字即可。

stdin

當輸入選擇 FILE_INPUT 時會覆寫 stdio.h 對 stdin 的定義。

本巨集僅用於將 freed() 等未被包裝的輸入函式指向正確的輸入位置,在被包裝的函式中,內部會強制將流導向定義的 fileIn 或 termIn 。

termIn

終端輸入流

termOut

終端輸出流

termErr

終端錯誤流

fileIn

檔案輸入流

fileOut

檔案輸出流

fileCmp

檔案比對流

IO 修正

LFFIX

定義是否將 gets(),fgets() 讀入字串末端的換行符號 ('\n') 移除

0 = 不移除字串尾的換行符號
1 = 移除字串尾的換行符號

IO 模式

使用 wrapper 包裝平常會使用到的輸入輸出方式。
IO 模式是預設為 F_TF,你可以在 naukri.h 進行更改,若只是要暫時的更改做測試則在 main.c 的 #include <naukri.h> 之前定義你要的模式 Ex:

#define F_TF
#include <stdio.h>
#include <naukri.h>

就會變成 F_TF 模式。

NO_WRAPPER

不包裝,也就是使用原生的 IO 模式

T_T

使用終端機作為輸入,並將結果輸出至終端機,和不包裝一樣,差別在它能讓不接受回傳值時的警告消失。

T_F

使用終端機作為輸入,並將結果輸出至 FILE_OUTPUT。

T_TF

使用終端機作為輸入,並將結果輸出至終端機和 FILE_OUTPUT。

F_T

使用 FILE_INPUT 作為輸入,並將結果輸出至終端機。

F_F

使用 FILE_INPUT 作為輸入,並將結果輸出至 FILE_OUTPUT。

F_TF

使用 FILE_INPUT 作為輸入,並將結果輸出至終端機和 FILE_OUTPUT。

F_C

使用 FILE_INPUT 作為輸入,並將結果輸出至 FILE_COMPARE,這是給 judge.c 使用的巨集。

F_TC

使用 FILE_INPUT 作為輸入,並將結果輸出至終端機和 FILE_COMPARE,這是給 judge.c 使用的巨集。

被包裝的函式

除了輸入輸出(參照IO 模式)位置外,他們不會對你的程式造成任何影響,你可以像沒有包裝時一樣使用他們。但要注意為了讓模組能夠正常的運行,這些被包裝的函式可能會產生額外的運算。

  • scanf(_Format, …)
  • gets(_Buffer)
  • fgets(_Buffer, _MaxCount, _Stream)
  • getchar()
  • printf(_Format, …)
  • puts(_Buffer)
  • putchar(_Character)

注意事項

  • judge.c 最上方會有預設的引入,這是使用程式碼進行判斷時的必要引入,請不要將它刪掉,如果不慎誤刪在 naukri.h 最底部有一個被註解掉的備份可以還原。

  • 時間判斷是使用 CPU 的 clock 數來計算,因此在終端機等候輸入和使用中斷點 Debug 的時都會被計入,若想要獲得較正確的時間評估請使用 FILE_INPUT 做輸入並關閉所有中斷點。

  • 模組中使用的全域函式或變數皆以雙底線開頭、單底線結尾(__func_()),是為了避免和使用者定義的函式衝到,請不要使用這種命名方式。

  • main.c 的 main() 會被用巨集定義成 __main_()、 judge.c 的 main() 則會被定義成 __judge_(),這些是為了先載入模組的必要定義,模組載入後會自己呼叫 __main_() 和 __judge_() ,不必擔心。

  • 如果 main.c 和 judge.c 的變數或函式撞名,系統會報錯並顯示該變數(函式)已經在 judge.obj 定義過了,這時候只要把 judge.c 裡面的撞名變數(函式)前面加上 static 前綴即可。